/**
 * Copyright (c) 2010 XXXXX
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ar.edu.itba.ia2010.geneticos.motor;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.Validate;

import ar.edu.itba.ia2010.geneticos.motor.api.CacheableCromosoma;
import ar.edu.itba.ia2010.geneticos.motor.api.Cromosoma;
import ar.edu.itba.ia2010.geneticos.motor.api.EstrategiaCorte;
import ar.edu.itba.ia2010.geneticos.motor.api.EstrategiaGeneracionCromosomas;
import ar.edu.itba.ia2010.geneticos.motor.api.EstrategiaReproduccionCromosomas;
import ar.edu.itba.ia2010.geneticos.motor.api.EstrategiaSeleccionCromosomas;

/**
 * TODO Descripcion de la clase. Los comenterios van en castellano.
 * 
 * 
 * @author Juan F. Codagnone
 * @since Mar 16, 2010
 * @param <C> Tipo del gen
 */
public class MotorGenetico<C> {
    private final EstrategiaGeneracionCromosomas<C> estrategiaGeneracion;
    private final EstrategiaSeleccionCromosomas<C> estrategiaSeleccion;
    private final EstrategiaReproduccionCromosomas<C> 
        estrategiaReproduccionCromosomas;
    private final EstrategiaSeleccionCromosomas<C> estrategiaRemplazo;
    private final EstrategiaCorte<C> estrategiaCorte;

    /** motor */
    public MotorGenetico(
       final EstrategiaGeneracionCromosomas<C> estrategiaGeneracion,
       final EstrategiaSeleccionCromosomas<C> estrategiaSeleccion,
       final EstrategiaReproduccionCromosomas<C> estrategiaReproduccionCromosomas,
       final EstrategiaSeleccionCromosomas<C> estrategiaRemplazo,
       final EstrategiaCorte<C> estrategiaCorte) {
        
        Validate.notNull(estrategiaGeneracion);
        Validate.notNull(estrategiaSeleccion);
        Validate.notNull(estrategiaReproduccionCromosomas);
        Validate.notNull(estrategiaRemplazo);
        Validate.notNull(estrategiaCorte);
        
        this.estrategiaGeneracion = estrategiaGeneracion;
        this.estrategiaSeleccion = estrategiaSeleccion;
        this.estrategiaReproduccionCromosomas = estrategiaReproduccionCromosomas;
        this.estrategiaRemplazo = estrategiaRemplazo;
        this.estrategiaCorte = estrategiaCorte;
    }
    
    /** @see Runnable#run() */
    public final List<Cromosoma<C>> run() {
        final List<Cromosoma<C>> poblacion = estrategiaGeneracion.generate();
        final List<Cromosoma<C>> tmp = new ArrayList<Cromosoma<C>>(poblacion.size() 
                + estrategiaSeleccion.getToSelect());
        
        while(estrategiaCorte.nextAge(poblacion)) {
            tmp.clear();
            tmp.addAll(poblacion);
            tmp.addAll(estrategiaReproduccionCromosomas.reproduction(
                    estrategiaSeleccion.select(poblacion)));
                    
            // limpio el cache de todos los individuos
            for(Cromosoma<C> c : tmp) {
                if(c instanceof CacheableCromosoma) {
                    ((CacheableCromosoma)c).setAptitud(null);
                }
            }
            poblacion.clear();
            poblacion.addAll(estrategiaRemplazo.select(tmp));
        }
        
        return poblacion;
    }
}
